package com.csjy.migration.hnnd.business;

import com.csjy.migration.hnnd.*;
import com.csjy.migration.hnnd.annotation.BusinessDataConverter;
import com.csjy.migration.hnnd.annotation.Dict;
import com.csjy.migration.hnnd.dict.*;

import java.sql.*;
import java.util.*;

/**
 * 流程实例
 */
@BusinessDataConverter(
    insertSql = "INSERT INTO ACT_HI_PROCINST\n" +
        "(ID_, PROC_INST_ID_, BUSINESS_KEY_, PROC_DEF_ID_, START_TIME_, END_TIME_, DURATION_,\n" +
        " START_USER_ID_, START_ACT_ID_, END_ACT_ID_, SUPER_PROCESS_INSTANCE_ID_, DELETE_REASON_, TENANT_ID_, PROCESS_STOP_CAUSE_)\n" +
        "VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
    updateSql = "UPDATE ACT_HI_PROCINST " +
        "           SET PROC_INST_ID_=?, BUSINESS_KEY_=?, PROC_DEF_ID_=?, START_TIME_=?, END_TIME_=?, DURATION_=?, START_USER_ID_=?, START_ACT_ID_=?, END_ACT_ID_=?, SUPER_PROCESS_INSTANCE_ID_=?, DELETE_REASON_=?, TENANT_ID_=?, PROCESS_STOP_CAUSE_=? " +
        "           WHERE ID_ = ?",
    findMigratedIdListSql = "SELECT ID_ FROM ACT_HI_PROCINST WHERE TENANT_ID_ = ? ",
    seq = 50001
)
public class ActHiProcinst extends AbstractBusiness {

  // TODO: 可迁移的正在运行中的流程类型
  private static List<String> runningWorkflowCodeList = Arrays.asList(new String[]{
  });

  public ActHiProcinst(DbUtil sourceDbUtil, DbUtil targetDbUtil, SourceBusinessData sourceData, ProgramArgument programArgument, String projectId) throws SQLException {
    super(sourceDbUtil, targetDbUtil, sourceData, programArgument, projectId);
  }

  @Override
  public void migrate() throws Exception {
    // ========源数据库相关表=========//
    // JBPM_PROCESSINSTANCE

    // ========目标数据库相关表=======//
    // ACT_HI_PROCINST
    // ACT_HI_DETAIL（主要根据NAME_为PRO_ID的记录关联查询流程实例的)
    // ACT_HI_VARINST (主要从中取lastHandleUser 、lastHandleRemartk、lastHandleTime)
    // MIGRATION_ID_MAP(source_id,source_name,category,target_id,target_name,target_key)

    try {
      // 查询出源数据库中已迁移完成的流程实例
      String sQueryProcInstListSql ="\n" +
              "SELECT \n" +
              "   biwr.ITEMNO, biwr.WORKFLOWNO ,biwr.WFNAME, biwr.WFDISPLAYNAME, biwr.BEGINTIME ,biwr.ENDTIME,BIWR.CREATEPERSON,biwr.ENDPERSON,\n" +
              "   jp.ID_, jp.PROCESSDEFINITION_ ,jp.START_ ,jp.END_, \n" +
              "   fe.EMPNAME,\n" +
              "   (SELECT COUNT(*) COUNT_ FROM JBPM_TASKINSTANCE jt WHERE jt.ISOPEN_ = 1 AND jt.PROCINST_ = biwr.WORKFLOWNO) OPEN_TASK_COUNT \n" +
              "FROM BT_ITEM_WORKFLOW_REC biwr \n" +
              "JOIN JBPM_PROCESSINSTANCE jp ON biwr.WORKFLOWNO  = jp.ID_ \n" +
              "LEFT JOIN FT_EMPLOYEE fe ON fe.TOPORGID = (" +
              "         case when SUBSTR(BIWR.ENDPERSON ,0, INSTR(BIWR.ENDPERSON ,'.')-1)='HNY' THEN 9051 ELSE 17575 END" +
              ") AND fe.EMPCODE = SUBSTR(biwr.ENDPERSON ,INSTR(biwr.ENDPERSON,'.')+1)\n" +
              "WHERE biwr.ITEMNO = '"+this.projectId+"'\n";

      ActHiTaskinst actHiTaskinst = new ActHiTaskinst(sourceDbUtil,targetDbUtil,sourceData,programArgument,projectId);
      ActHiDetail actHiDetail = new ActHiDetail(sourceDbUtil,targetDbUtil,sourceData,programArgument,projectId);
      WorkflowData workflowData = new WorkflowData(sourceDbUtil,targetDbUtil,sourceData,programArgument,projectId);

      List<Map> jbpmProcessInstanceList = this.sourceDbUtil.selectByParams(sQueryProcInstListSql, new ArrayList());

      // workflowIds参数
      List<String> workflowIdList = new ArrayList<>();
      if(!this.programArgument.getWorkflowIds().equals("")){
        workflowIdList = Arrays.asList(this.programArgument.getWorkflowIds().split(","));
      }

      // workflowCodes参数
      List<String> workflowCodeList = new ArrayList<>();
      if(!this.programArgument.getWorkflowCodes().equals("")){
        workflowCodeList = Arrays.asList(this.programArgument.getWorkflowCodes().split(","));
      }

      for(Map row : jbpmProcessInstanceList) {
        try {


          // 判断 workflowIds 和 workflowCodes 参数
          if(!workflowIdList.isEmpty()) {
            if(!workflowIdList.contains(row.get("ID_").toString())){
              continue;
            }
          } else {
            if(!workflowCodeList.isEmpty() && !workflowCodeList.contains(row.get("WFNAME").toString())) {
              continue;
            }
          }

//          if(this.programArgument.getOnlyMigrateUndoneWorkflow().equals("1") && row.get("OPEN_TASK_COUNT").toString().equals("0")) {
//            continue;
//          }

          // 针对正在进行中的流程，有两种迁移策略，一种是完全覆盖（以 老系统中为准)，另外一种就是仅迁移一次(默认采用这种策略)
          if(BusinessTool.migratedUndoneWorkflowIdList.contains(row.get("ID_").toString() + "-JW") && this.programArgument.getCoverUndoneWorkflow().equals("0")){
            continue;
          }



          if(this.programArgument.getOnlyWorkflowData().equals("1")){
            workflowData.customMigrate(row);
            continue;
          }

          actHiTaskinst.customMigrate(row);

          ActHiVarinst actHiVarInst = new ActHiVarinst(sourceDbUtil,targetDbUtil,sourceData,programArgument,projectId, row.get("ID_").toString());
          this.migrateActHiVarinst(actHiVarInst, row);

          TSBasebus tsBasebus = new TSBasebus(sourceDbUtil, targetDbUtil, sourceData, programArgument, projectId);
          tsBasebus.customMigrate(row);

          actHiDetail.customMigrate(row);
          workflowData.customMigrate(row);

          insertWorkflowMiddleRecord(row);

          // 判断是否需要覆盖迁移
          int needMigratedResult = this.needMigrated(row.get("ID_")+"-JW");
          if(needMigratedResult == 0) {
            continue;
          }

          // 单条插入或更新
          if(needMigratedResult == 1) {
            this.targetDbUtil.updateByParams(updateSql,this.buildValues(row),true);
          } else {
            this.targetDbUtil.updateByParams(insertSql,this.buildValues(row));
          }
        } catch(Exception e) {
          throw new Exception(String.format("流程实例[%s]迁移失败:%s\n",row.get("ID_"),e.getMessage()));
        }
      }
      actHiTaskinst.start();
      actHiDetail.start();

    } catch (Exception e) {
      throw new Exception("流程实例数据迁移过程中出现异常,:" + e.getMessage());
    }
  }

  public void migrateActHiVarinst(ActHiVarinst actHiVarinst, Map<String,Object> procInstRow) throws SQLException {
    String procInstId = procInstRow.get("ID_")+"-JW";
    String createBy = BusinessTool.getTaskRealActorId(procInstRow.get("CREATEPERSON").toString(),procInstRow.get("BEGINTIME"));

    Map<String, Object> map = new HashMap<>();
    map.put("lastHandleUser", procInstRow.get("EMPNAME").toString());
    map.put("lastHandleTime", null);
    map.put("lastHandleRemark", null);
    map.put("applyUserId",createBy);

    map.put("ID", procInstId);
    map.put("CREATE_NAME",BusinessTool.getEmpNameByEmpCode(createBy));
    map.put("CREATE_BY",createBy);
    map.put("CREATE_DATE",null);
    map.put("UPDATE_NAME",null);
    map.put("UPDATE_BY",null);
    map.put("UPDATE_DATE",null);
    map.put("SYS_ORG_CODE",null);
    map.put("SYS_COMPANY_CODE","002");
    map.put("BPM_STATUS","1");
    map.put("PRO_ID", this.projectId);
    map.put("BPM_DATA_ID",procInstId);
    map.put("BPM_FORM_CONTENT_URL", String.format(DictTool.getTargetDictCode(FormContentUrl.class, procInstRow.get("WFNAME").toString()), procInstId, this.projectId));
    map.put("BPM_FORM_CONTENT_URL_MOBILE", String.format(DictTool.getTargetDictCode(FormContentUrl.class, procInstRow.get("WFNAME").toString()), procInstId, this.projectId));
    map.put("BPM_FORM_KEY",DictTool.getTargetDictCode(BpmFormKey.class, ""));
    map.put("bpm_biz_title",DictTool.getTargetDictCode(BpmBizTitle.class,""));
    map.put("bpm_proc_deal_style", "ndCustom");
    map.put("JG_LOCAL_PROCESS_ID", procInstId);

    // 正在进行中的流程
    if(!procInstRow.get("OPEN_TASK_COUNT").toString().equals("0")) {
      String newProcDefId = DictTool.getTargetDictCode(NewProcessDefId.class, BusinessTool.getWorkflowRealWfName(procInstRow));
      if(!newProcDefId.equals(procInstRow.get("WFNAME").toString())) {
        map.put("jwframeFlag","undoneContinue");
      } else {
        map.put("jwframeFlag","undone");
      }
    } else {
      map.put("jwframeFlag","done");
    }
    actHiVarinst.customMigrate(map);

  }

  public void insertWorkflowMiddleRecord(Map row) throws SQLException {
    String workflowMiddleTableName = DictTool.getTargetDictCode(WorkflowMiddleTableName.class,BusinessTool.getWorkflowRealWfName(row));
    if(workflowMiddleTableName.equals(row.get("WFNAME").toString())) {
      return;
    }

    this.targetDbUtil.updateByParams("delete from "+workflowMiddleTableName+" where id = ?"
        , Arrays.asList(row.get("ID_").toString()+"-JW"));

    String insertSql = "INSERT INTO "+workflowMiddleTableName+"\n" +
        "(ID, CREATE_NAME, CREATE_BY, CREATE_DATE, UPDATE_NAME, UPDATE_BY, UPDATE_DATE, SYS_ORG_CODE, SYS_COMPANY_CODE, BPM_STATUS, PRO_ID)\n" +
        "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
    String createBy = BusinessTool.getTaskRealActorId(row.get("CREATEPERSON").toString(), row.get("BEGINTIME"));

    List values = new ArrayList();
    // ID
    values.add(row.get("ID_").toString()+"-JW");
    // CREATE_NAME
    values.add(BusinessTool.getEmpNameByEmpCode(createBy));
    // CREATE_BY
    values.add(createBy);
    // CREATE_DATE
    values.add(row.get("BEGINTIME"));
    // UPDATE_NAME
    values.add(null);
    // UPDATE_BY
    values.add(null);
    // UPDATE_DATE
    values.add(null);
    // SYS_ORG_CODE
    values.add(null);
    // SYS_COMPANY_CODE
    values.add("002");
    // BPM_STATUS
    values.add(row.get("OPEN_TASK_COUNT").toString().equals("0") ? "3" : "2");
    // PRO_ID 项目编号
    values.add(this.projectId);
    this.targetDbUtil.updateByParams(insertSql, values, false);

  }

  public List buildValues(Map row) throws SQLException {

    String procInstId = row.get("ID_").toString()+"-JW";
    Timestamp startTime = null;
    Timestamp endTime ;

    if(row.get("BEGINTIME") != null && !row.get("BEGINTIME").toString().equals("")) {
      startTime = (java.sql.Timestamp)row.get("BEGINTIME");
    }

    List values = new ArrayList();
    values.add(procInstId);
    values.add(procInstId);
    //    BUSINESS_KEY_
    values.add(procInstId);
    values.add(BusinessTool.getProcDefId(row));
    values.add(startTime);

    if(row.get("ENDTIME") != null && !row.get("ENDTIME").toString().equals("")) {
      endTime = (java.sql.Timestamp)row.get("ENDTIME");
      values.add(endTime);
      values.add(endTime.getTime() - startTime.getTime());
    }else {
      values.add(null);
      values.add(null);
    }
    // START_USER_ID_     CREATEPERSON: HNY.xxx 或者 HNYCS.xxx
    values.add(BusinessTool.getTaskRealActorId(row.get("CREATEPERSON").toString(), row.get("BEGINTIME")));
    // START_ACT_ID_
    values.add("start1");
    // END_ACT_ID_
    values.add(row.get("OPEN_TASK_COUNT").toString().equals("0") ? "end" : "jwframe_undone");
    //SUPER_PROCESS_INSTANCE_ID_
    values.add(null);
    //DELETE_REASON_
    values.add(null);
    //TENANT_ID_
    values.add(this.projectId);
    //PROCESS_STOP_CAUSE_a
    values.add(null);

    return values;

  }

}
